#ifndef AFCORE_COMMON_LOG_LOGGER_
#define AFCORE_COMMON_LOG_LOGGER_

#include <vector>
#include <string>

#include "logcommon.h"
#include "log_msg.h"
#include "log_backtracer.h"

namespace afcore {

/// @brief  日志
namespace log {

/// @brief  记录器
class AFCORE_COMMON_API CLogger {
public:
  /// @brief  显示构造函数附带记录器名称
  /// @param  name    记录器名称
  explicit CLogger(std::string name)
    : name_(std::move(name))
    , appenders_() {
  }

  /// @brief  模板构造含糊附带记录器名称与追加器范围
  /// @param  name    记录器名称
  /// @param  begin   追加器容器开始迭代器
  /// @param  end     追加器容器结束迭代器
  template<typename Iter>
  CLogger(std::string name, Iter begin, Iter end)
    : name_(std::move(name))
    , appenders_(begin, end) {
  }

  /// @brief  构造函数附带记录器名称与追加器初始化列表
  /// @param  name        记录器名称
  /// @param  appenders   追加器初始化列表
  CLogger(std::string name, RAppenderInitList appenders)
    : CLogger(std::move(name), appenders.begin(), appenders.end()) {
  }

  /// @brief  构造函数附带记录器名称与单个追加器
  /// @param  name                记录器名称
  /// @param  single_appender     单个追加器 委托给初始化列表处理
  CLogger(std::string name, RAppenderSptr single_appender)
    : CLogger(std::move(name), {std::move(single_appender)}) {
  }

  /// @brief  默认析构函数
  virtual ~CLogger() = default;

  /// @brief  拷贝构造函数
  /// @param  that    记录器
  CLogger(const CLogger& that);
  /// @brief  移动构造函数
  /// @param  [out]   that    记录器
  CLogger(CLogger&& that) noexcept;
  /// @brief  拷贝赋值
  /// @param  that    记录器
  CLogger& operator=(CLogger that) noexcept;
  /// @brief  交换两个记录器
  /// @param  [out]   that    记录器
  void Swap(CLogger& that) noexcept;

  /// @brief  记录日志
  /// @tparam ...Args     额外参数
  /// @param  src_info    源文件信息
  /// @param  l           日志级别
  /// @param  fmt         格式化字符串
  /// @param  ...args     额外参数
  template<typename... Args>
  void Log(SSrcLocInfo src_info, afcore::log::ELogLevel l, RStringView fmt, const Args&... args) {
    bool log_enabled = ShouldLog(l);
    bool traceback_enabled = ShouldBacktrace();
    if (!log_enabled && traceback_enabled) {
      return;
    }

    try {
      RMemoryBuf buf;
      fmt::format_to(buf, fmt, args...);
      SLogMessage log_msg(src_info, name_, l, RStringView(buf.data(), buf.size()));
      DoLog(log_msg, log_enabled, traceback_enabled);
    } catch (const std::exception& ex) {
      DoErrHandler(ex.what());
    } catch (...) {
      DoErrHandler("Unknown exception in logger");
    }
  }

  template<typename... Args>
  void Log(ELogLevel l, RStringView fmt, const Args&... args) {
    Log(SSrcLocInfo{}, l, fmt, args...);
  }

  template<typename... Args>
  void Trace(RStringView fmt, const Args&... args) {
    Log(kLogLevelTrace, fmt, args...);
  }

  template<typename... Args>
  void Debug(RStringView fmt, const Args&... args) {
    Log(kLogLevelDebug, fmt, args...);
  }

  template<typename... Args>
  void Info(RStringView fmt, const Args&... args) {
    Log(kLogLevelInfo, fmt, args...);
  }

  template<typename... Args>
  void Warn(RStringView fmt, const Args&... args) {
    Log(kLogLevelWarn, fmt, args...);
  }

  template<typename... Args>
  void Error(RStringView fmt, const Args&... args) {
    Log(kLogLevelError, fmt, args...);
  }

  template<typename... Args>
  void Fatal(RStringView fmt, const Args&... args) {
    Log(kLogLevelFatal, fmt, args...);
  }

  template<typename T>
  void Log(ELogLevel l, const T& msg) {
    Log(SSrcLocInfo{}, l, msg);
  }

  template<class T, typename std::enable_if<std::is_convertible<const T&, RStringView>::value, T>::type* = nullptr>
  void Log(SSrcLocInfo src_info, ELogLevel l, const T& msg) {
    Log(src_info, l, RStringView{msg});
  }

  /// @brief  记录日志
  /// @param  src_info    源文件信息
  /// @param  l           日志级别
  /// @param  msg         日志信息
  void Log(SSrcLocInfo src_info, ELogLevel l, RStringView msg) {
    bool log_enabled = ShouldLog(l);
    bool traceback_enabled = ShouldBacktrace();
    if (!log_enabled && !traceback_enabled) {
      return;
    }
    SLogMessage log_msg(src_info, name_, l, msg);
    DoLog(log_msg, log_enabled, traceback_enabled);
  }

  void Log(ELogLevel l, RStringView msg) {
    Log(SSrcLocInfo{}, l, msg);
  }

  template<typename T>
  void Trace(const T& msg) {
    Log(kLogLevelTrace, msg);
  }

  template<typename T>
  void Debug(const T& msg) {
    Log(kLogLevelDebug, msg);
  }

  template<typename T>
  void Info(const T& msg) {
    Log(kLogLevelInfo, msg);
  }

  template<typename T>
  void Warn(const T& msg) {
    Log(kLogLevelWarn, msg);
  }

  template<typename T>
  void Error(const T& msg) {
    Log(kLogLevelError, msg);
  }

  template<typename T>
  void Fatal(const T& msg) {
    Log(kLogLevelFatal, msg);
  }

  /// @brief  消息的日志级别是否需要记录
  /// @param  msg_level   日志的消息级别
  /// @return true        需要记录
  /// @return false       不需要记录
  bool ShouldLog(ELogLevel msg_level) const {
    return msg_level >= level_.load(std::memory_order_relaxed);
  }

  /// @brief  消息的日志级别是否需要追踪
  /// @return true        需要追踪
  /// @return false       不需要追踪
  bool ShouldBacktrace() const {
    return tracer_.Enabled();
  }

  /// @brief  设置格式器
  /// @param  formatter           格式器
  void SetFormatter(RFormatterUptr formatter);

  /// @brief  设置格式匹配器
  /// @param  pattern             匹配模式
  /// @param  time_type           匹配时间格式
  void SetPattern(std::string pattern, EPatternTimeType time_type = EPatternTimeType::kPatternTimeTypeLocal);

  /// @brief  设置追踪器可用
  /// @param  msg_max             最大记录深度
  void EnableBacktrace(size_t msg_max);

  /// @brief  设置追踪器不可用
  void DisableBacktrace();

  /// @brief  转储
  void DumpBacktrace();

  /// @brief  刷新
  void Flush();

  /// @brief  复制记录器 虚函数
  /// @param  logger_name         记录器名称
  /// @return 复制后的记录器
  virtual RLoggerSptr CLone(std::string logger_name);

  /// @brief  获取记录器日志级别
  /// @return 当前记录器最低日志级别
  ELogLevel GetLogLevel() const;

  /// @brief  设置记录器最低日志级别
  /// @param  log_level       当前记录器最低日志级别
  void SetLogLevel(ELogLevel log_level);

  /// @brief  获取记录器名称
  /// @return 记录器名称
  const std::string& GetName() const;

  /// @brief  获取刷新级别
  /// @return 刷新级别
  ELogLevel GetFlushLevel() const;

  /// @brief  设置刷新级别
  /// @param  l               刷新级别
  void SetFlushLevel(ELogLevel l);

  /// @brief  获取追加器 常量引用
  /// @return 常量引用追加器
  const std::vector<RAppenderSptr>& GetAppenders() const;

  /// @brief  获取追加器
  /// @return 追加器
  std::vector<RAppenderSptr>& GetAppenders();

  /// @brief  设置用户自定义错误处理程序
  void SetCustomErrHandler(RErrHanlder handler);

protected:
  /// @brief  是否刷新
  /// @param  msg                 日志信息
  bool ShouldFlush(const SLogMessage& msg);
  /// @brief  记录日志
  /// @param  log_msg             日志信息
  /// @param  log_enabled         记录标识
  /// @param  traceback_enabled   追踪标识
  void DoLog(const SLogMessage& log_msg, bool log_enabled, bool traceback_enabled);
  /// @brief  所有追加器记录日志
  /// @param  msg                 日志信息
  virtual void AppenderDoLog(const SLogMessage& msg);
  /// @brief  刷新
  virtual void DoFlush();
  /// @brief  转储追踪信息
  void DoDumpBacktrace();
  /// @brief  错误处理
  /// @param  msg                 日志信息
  void DoErrHandler(const std::string& msg);

protected:
  std::string name_;                                    ///< 记录器名称
  std::vector<RAppenderSptr> appenders_;                ///< 接收器集合
  std::atomic<uint8_t> level_ {kLogLevelInfo};        ///< 日志级别
  std::atomic<uint8_t> flush_level_ {kLogLevelOff};   ///< 刷新级别
  RErrHanlder custom_err_hanlder_ {nullptr};            ///< 用户自定义错误处理
  CLogBackTracer tracer_;                               ///< 追踪器
};

/// @brief  交换两个记录器
/// @param  [out]   a   记录器a
/// @param  [out]   b   记录器b
void Swap(CLogger& a, CLogger& b);

} // !namespace log

} // !namespace afcore

#endif //! AFCORE_COMMON_LOG_LOGGER_
